package midend;

import midend.*;
import midend.IR_Type.*;
import midend.IR_Module;
import midend.IR_Instruction.*;
import midend.IR_Value.IR_BaseBlock;
import midend.IR_Value.IR_FuncBlock;
import midend.IR_Value.IR_Global_Value;
import midend.IR_Value.IR_Value;

import java.util.ArrayList;
import java.util.HashSet;

public class Func_Side_Effect_Analysis {
    private static HashSet<IR_FuncBlock> visited = new HashSet<>();
    public static void sideEffectAnalysis(IR_Module module) {
        // 计算函数之间的调用和被调用关系
        module.calc_CallRelation();
        visited = new HashSet<>();
        for (IR_FuncBlock function : module.getFuncBlocks()) {
            if (function.get_FuncName().equals("@main")) {
                visited.add(function);
                function.setSideEffect();
                continue;
            }
            if (analysisFunc(function)) {
                setSideEffect(function);
            }
        }
    }

    //函数副作用分析：不会对内存和IO产生影响
    //1.不调用库函数，会影响IO
    //2.若有副作用，则所有调用该函数的函数都有副作用
    //3.不对全局变量以及数组指针进行改变
    public static boolean analysisFunc(IR_FuncBlock function) {
        for (IR_BaseBlock bb : function.get_bb_List()) {
            for (Instruction instruction : bb.get_Instruction_List()) {
                if (instruction instanceof Call_Instruction) {
                    IR_FuncBlock callFunc = ((Call_Instruction) instruction).get_funcBlock();
                    if (callFunc.isLib()) {
                        function.setSideEffect();
                        return true;
                    } else {
                        if (callFunc.isSideEffect()) {
                            function.setSideEffect();
                            return true;
                        }
                    }
                } else if (instruction instanceof Store_Instruction) {
                    IR_Value  ptr = instruction.get_op().get(2); // store的目标地址
                    IR_Value value = instruction.get_op().get(1); // store的值
                    Pointer_Instruction origin = function.res_From_GetElePtr(ptr);
                    if (ptr instanceof IR_Global_Value || (origin != null && origin.get_base() instanceof IR_Global_Value)) {
                        // ptr是全局变量它的来源是全局变量数组
                        function.setSideEffect();
                        return true;
                    } else if (function.isParam(ptr) || (origin != null && function.isParam(origin.get_base()))) {
                        // ptr是函数参数或者它的来源是函数参数
                        function.setSideEffect();
                        return true;
                        }
                    else if (function.isParam(value) && value.get_Type() instanceof IR_Pointer){
                        //    define i32 @QuickSort(i32* %QuickSort0138, i32 %QuickSort1139, i32 %QuickSort2140){
//                            QuickSortEntry20:
//                            %arr141 = alloca i32*, align 4
//                            store i32* %QuickSort0138, i32** %arr141, align 4
                        function.setSideEffect();
                        return true;
                    }
                }
            }
        }
        //到这里基本就没有副作用了
        return false;
    }

    public static void setSideEffect(IR_FuncBlock function) {
        if (visited.contains(function)) {
            return;
        }
        visited.add(function);
        for (IR_FuncBlock function1 : function.getBeCalledList()) {
            function1.setSideEffect();
            setSideEffect(function1);
        }
    }


}
